package org.yunai.swjg.server.module.item.operation.move;

import org.yunai.swjg.server.core.constants.SysMessageConstants;
import org.yunai.swjg.server.module.item.container.Bag;
import org.yunai.swjg.server.module.item.container.CommonBag;
import org.yunai.swjg.server.module.item.vo.Item;
import org.yunai.swjg.server.module.player.vo.Player;
import org.yunai.swjg.server.rpc.message.S_C.S_C_SysMessageReq;

/**
 * 道具移动基类
 * User: yunai
 * Date: 13-6-7
 * Time: 上午9:20
 */
public abstract class AbstractItemMoveOperation implements ItemMoveOperation {

    /**
     * 判断是否能够移动<br />
     * 以下操作会导致无法移动：
     * <pre>
     *     1. 道具为空
     *     2. 目标背包位置错误。该情况会发送消息
     *     3. 道具就在目标位置
     *     4. 移动操作不合适
     *     5. 子类实现判断是否可以移动{@link #canMoveImpl(org.yunai.swjg.server.module.player.vo.Player, org.yunai.swjg.server.module.item.vo.Item, org.yunai.swjg.server.module.item.container.CommonBag, int)}
     * </pre>
     *
     * @param player  玩家信息
     * @param item    道具
     * @param toBag   目标背包
     * @param toIndex 目标背包位置
     * @return 移动结果
     */
    private boolean canMove(Player player, Item item, CommonBag toBag, int toIndex) {
        if (Item.isEmpty(item)) {  // 空道具无法移动
            return false;
        }
        if (toBag == null || Bag.BagType.isNullBag(toBag.getBagType())) { // 背包错误
            player.message(new S_C_SysMessageReq(SysMessageConstants.ITEM_BAG_TYPE_ERROR));
            return false;
        }
        if (!toBag.checkIndex(toIndex)) { // 当toIndex范围不对时，认为背包已满
            player.message(new S_C_SysMessageReq(SysMessageConstants.ITEM_BAG_FULL));
            return false;
        }
        return !item.isAtThisSlot(toBag.getBagType(), toIndex) // 就在当前位置，不能进行这样的移动
                && isSuitable(player, item, toBag, toIndex) // 再验证一次，是否是合法的移动操作
                && canMoveImpl(player, item, toBag, toIndex);
    }

    /**
     * 子类实现判断是否能够移动
     *
     * @param player  玩家信息
     * @param item    道具
     * @param toBag   目标背包
     * @param toIndex 目标背包位置
     * @return 是否能够移动
     */
    protected abstract boolean canMoveImpl(Player player, Item item, CommonBag toBag, int toIndex);

    @Override
    public final boolean move(Player player, Item item, CommonBag toBag, int toIndex) {
        return canMoveImpl(player, item, toBag, toIndex) && moveImpl(player, item, toBag, toIndex);
    }

    /**
     * 子类实现移动，并返回移动结果
     *
     * @param player  玩家信息
     * @param item    道具
     * @param toBag   目标背包
     * @param toIndex 目标背包位置
     * @return 移动结果
     */
    protected abstract boolean moveImpl(Player player, Item item, CommonBag toBag, int toIndex);
}